#!/usr/bin/env python
# -*- coding:utf-8 -*-
# @Time   : 2021/7/9 22:32
# @Author : cjw
from typing import Optional, List
from pydantic import BaseModel, Field
from datetime import date

from fastapi import APIRouter, Path, Query, Cookie, Header
from enum import Enum

app03 = APIRouter()

"""路径参数和数字验证"""


@app03.get('/path/parameters', description='没有参数的路径参数', name='没有传参的路径参数')
def path_parameter01():
    return {'message': '这是一个消息提示'}


# 函数的顺序，就是路由的顺序，parameters='parameters'，则调用第一个接口
@app03.get('/path/{parameters}', description='有参数的路径参数', name='有传参的路径参数')
def path_parameter02(parameters: str):
    return {'message': parameters}


class CityName(str, Enum):
    BEI_JIN = 'bei jin china'
    SHANG_HAI = 'shang hai china'


@app03.get('/enum/{city}', name='枚举类型路径参数')
def latest(city: CityName):
    if city == CityName.SHANG_HAI:
        return {'city_name': city, 'confirmed': 1492, 'death': 7}
    elif city == CityName.BEI_JIN:
        return {'city_name': city, 'confirmed': 971, 'death': 9}
    return {'city_name': city, 'latest': 'unknown'}


@app03.get('/files/{file_path:path}', name='通过:path传递文件路径')
def filepath(file_path: str):
    return {'file path': file_path}


# 数据校验：...表示必输参数
@app03.get('/path_num/{num}', name='数字类型路径参数校验')
def path_parma_validate(
        num: int = Path(..., ge=1, le=10, title='你的数字路径参数校验', description='不可描述')
):
    return {'num': num}


"""查询参数和字符串验证"""


@app03.get('/query', name='查询参数')  # 给了默认值就是选填的参数，没有给默认值就是必填参数
def page_limit(page: int = 1, limit: Optional[int] = None):
    if limit:
        return {'page': page, 'limit': limit}
    return {'page': page}


@app03.get('/query/bool/conversion', name='查询参数布尔类型转换')
def type_conversion(param: bool = False):
    return param


@app03.get('/query/validations', name='查询参数字符串验证，参数别名')
def query_params_validate(
        value: str = Query(..., min_length=3, max_length=8, regex='^a'),
        values: List[str] = Query(['v1', 'v2'], alias='alias_name')
):
    return value, values


"""请求体和字段"""


class CityInfo(BaseModel):
    name: str = Field(..., example='Beijing')  # example是注解的作用，值不会被验证
    country: str
    country_code: str = None  # 给一个默认值
    country_population: int = Field(800, title='人口数量', description='国家的人口数量', ge=800)

    class Config:
        schema_extra = {
            'example': {
                'name': 'Shanghai',
                'country': 'China',
                'country_code': 'CN',
                'country_population': 1400000000
            }
        }


@app03.post('/request_body/city', name='请求体和参数校验')
def city_info(city: CityInfo):
    print(city.name, city.country, city.country_code, city.country_population)
    return city


"""多参数混合"""


@app03.put('/request_body/city/{name}', name='多参数混合')
def min_city_info(
        name: str,
        city01: CityInfo,
        city02: CityInfo,  # Body可以定义是多个的
        confirmed: int = Query(0, ge=0, description='确诊数'),
        death: int = Query(0, ge=0, description='死亡数')
):
    if name == 'Shanghai':
        return {'Shanghai': {'confirmed': confirmed, 'death': death}}
    return city01.dict(), city02.dict()


"""数据格式嵌套的请求体"""


class Data(BaseModel):
    # 定义数据格式嵌套的请求体
    city: Optional[List[CityInfo]] = None
    date: date  # 额外的数据类型
    confirmed: int = Field(0, ge=0, description='确诊数')
    deaths: int = Field(0, ge=0, description='死亡数')
    recovered: int = Field(0, ge=0, description='痊愈数')


@app03.put('/request_body/nested', name='数据格式嵌套的请求体')
def nested_models(data: Data):
    return data


"""Cookie 和 Header 参数"""


@app03.get('/cookie', name='cookie参数，需要使用postman测试')
def get_cookie(cookie_id: Optional[str] = Cookie(None)):
    # 定义cookie参数需要使用Cookie类，否则就是查询参数
    return {'cookie_id': cookie_id}


@app03.get('/header', name='header参数')
def header(user_agent: Optional[str] = Header(None, convert_underscores=True),
           x_token: List[str] = Header(None, convert_underscores=True)
           ):
    """
    有些HTTP代理服务器是不允许在请求头中带有下划线的，所以Header提供convert_underscores属性
    convert_underscores 会把user_agent转化为user-agent
    :param user_agent:
    :param x_token:
    :return:
    """
    return {'User-Agent': user_agent, 'x_token': x_token}
